/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bd.balancer;

import java.util.*;
import java.net.*;
import bd.util.*;
import java.util.*;
import java.io.*;
import javax.xml.ws.Endpoint;
import javax.jws.*;
import bd.master.*;

/**
 *
 * @author niyaz
 */
@WebService
public class Balancer {

    private ArrayList<bd.balancer.Cluster> clusters = new ArrayList<bd.balancer.Cluster>();
    String myAddress;
    Master myMaster = new Master();

    public Record select(String key) {
        Log.mes("Balancer select " + key);
        long hash = Hash.getHash(key);

        for (Cluster c : clusters) {
            if ((hash >= c.startHash) && (hash <= c.stopHash)) {
                return new Record(c.master.select(key).getName(), c.master.select(key).getPhone());
            }
        }

        return new Record();
    }

    ;

    public void insert(Record record) {
        Log.mes("Balancer insert " + record.name + " " + record.phone);

        long hash = Hash.getHash(record.name);

        for (Cluster c : clusters) {
            if ((hash >= c.startHash) && (hash <= c.stopHash)) {
                bd.artefacts.Record rec = new bd.artefacts.Record();
                rec.setName(record.name);
                rec.setPhone(record.phone);
                c.master.insert(rec);
                return;
            }
        }


    }

    ;

    public void delete(String key) {
        long hash = Hash.getHash(key);
        for (Cluster c : clusters) {
            if ((hash >= c.startHash) && (hash <= c.stopHash)) {
                c.master.delete(key);
            }
        }
    }

    ;

    public void RegisterMaster(String masterAddress) {
        Log.mes("RegisterMaster " + masterAddress);
        if (clusters.size() == 0) {
            VerginMasterRegister(masterAddress);
            return;
        }

        Cluster cluster = clusters.get(0);

        for (Cluster c : clusters) {
            if (c.master.numberOfRecords() > cluster.master.numberOfRecords()) {
                cluster = c;
            }
        }

        Cluster newCluster = new Cluster();

        newCluster.masterAddress = masterAddress;

        newCluster.startHash = cluster.startHash;
        newCluster.stopHash = (cluster.stopHash - cluster.startHash) / 2;

        cluster.startHash = (cluster.stopHash - cluster.startHash) / 2 + 1;
        cluster.stopHash = cluster.stopHash;

        newCluster.connect();


        bd.artefacts.Parameters par = new bd.artefacts.Parameters();
        par.setStartHash(newCluster.startHash);
        par.setStopHash(newCluster.stopHash);
        par.setBalancer(myAddress);
        newCluster.master.setParameters(par);





        clusters.add(newCluster);
        cluster.master.givePartOfBase(masterAddress, newCluster.startHash, newCluster.stopHash);
    }

    public void VerginMasterRegister(String masterAddress) {
        try {
            Log.mes("We are in VerginMasterRegister " + masterAddress);
            Cluster cluster = new Cluster();
            cluster.startHash = Hash.getStartHash();
            cluster.stopHash = Hash.getStopHash();
            cluster.masterAddress = masterAddress;

            cluster.connect();
            bd.artefacts.Parameters par = new bd.artefacts.Parameters();
            par.setStartHash(cluster.startHash);
            par.setStopHash(cluster.stopHash);
            par.setBalancer(myAddress);
            cluster.master.setParameters(par);
            clusters.add(cluster);
        } catch (Exception e) {
            Log.mes("Some shit in VerginMasterRegister");
        }
    }

    ;

    public void run() {
        System.out.println("Starting the balancer");
        myAddress = "http://localhost:9090/BalancerService/service";
        Endpoint.publish(myAddress, this);


        String myMasterAddress = "http://localhost:1111/MasterService/service";
        myMaster.publish(myMasterAddress);

        myMaster.connectBalancer(myAddress);


        control();

        System.exit(0);

    }

    private void control() {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = "";
        System.out.print("Enter a command. 'help' - if you wanna help\n");
        do {


            try {
                str = br.readLine();
            } catch (Exception e) {
            }
            ;



            if (str.equalsIgnoreCase("help")) {
                System.out.print("insert,select,delete,update\n");
            }

            if (str.equalsIgnoreCase("select")) {
                System.out.print("print name\n");
                try {
                    str = br.readLine();
                } catch (Exception e) {
                }
                ;

                Record r = select(str);
                printRecord(r);
            }

            if (str.equalsIgnoreCase("delete")) {
                System.out.print("print name\n");
                try {
                    str = br.readLine();
                } catch (Exception e) {
                }
                ;

                delete(str);

            }

            if (str.equalsIgnoreCase("exit")) {
                for (Cluster c : clusters) {
                    c.master.store();
                }
            }

            if (str.equalsIgnoreCase("store")) {
                for (Cluster c : clusters) {
                    c.master.store();
                }
            }

            if (str.equalsIgnoreCase("stat")) {
                int i = 0;
                System.out.println(clusters.size());
                for (Cluster c : clusters) {
                    System.out.println(++i);
                    System.out.println(c.masterAddress);
                    System.out.println(c.startHash);
                    System.out.println(c.stopHash);
                    System.out.println(c.master.numberOfRecords());
                    System.out.println("-----------");

                }

            }


            if (str.equalsIgnoreCase("insert")) {
                System.out.print("insert name\n");
                try {
                    str = br.readLine();
                } catch (Exception e) {
                }
                ;

                Record r = new Record();
                r.name = str;

                System.out.print("insert phone\n");
                try {
                    str = br.readLine();
                } catch (Exception e) {
                }
                ;

                r.phone = str;

                insert(r);
            }



            System.out.print("Enter a command. 'help' - if you wanna help\n");

        } while (!str.equalsIgnoreCase("exit"));

    }

    ;

    static void printRecord(Record r) {
        System.out.print(r.name + " " + r.phone + "\n");
    }

    ;
};
